#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <linux/input.h>

#include <errno.h>
#include <poll.h>
#include <sys/select.h>

#include "ubuntu_util.h"
#include "key_input.h"

#define KEYINPUT_INFO(...) fprintf(stdout, "\033[32m[KEYINPUT_INFO] %s(%d): \033[0m", __FUNCTION__, __LINE__),fprintf(stdout, __VA_ARGS__)
#define KEYINPUT_ERR(...) fprintf(stderr, "\033[31m[KEYINPUT_ERR] %s(%d): \033[0m", __FUNCTION__, __LINE__),fprintf(stderr, __VA_ARGS__)

typedef struct {
    int32_t fd;

    int32_t state; //0/ide 1/running 2/stopping
    int32_t holdIntervalMs; //按键按住时,定时触发事件间隔ms,写0不触发
    int32_t eventThreadCount; //正在处理的 KeyInputEventThread 线程数量

    int32_t keyNum; //最大同时按下按键数量
    int32_t *keyArray; //正在处理的按键,位置写按键代号,0为空闲

    void *priv;
    void (*callback)(void*, int, int);
} KeyInputStruct;

typedef struct {
    int32_t key; //按键
    int32_t value; //按键事件类型
    int32_t index; //在gKeyInput.keyArray[]中的序号
} KeyInputEnevtStruct;

static KeyInputStruct gKeyInput = {0};

//数组元素的设置和清除,返回位置
static int32_t _arrayAdd(int32_t *array, int32_t len, int32_t value)
{
    int32_t i;
    for (i = 0; i < len; i++) {
        if (array[i] == 0) {
            array[i] = value;
            return i;
        }
    }
    return 0;
}
static int32_t _arrayClear(int32_t *array, int32_t len, int32_t value)
{
    int32_t i;
    for (i = 0; i < len; i++) {
        if (array[i] == value) {
            array[i] = 0;
            return i;
        }
    }
    return 0;
}

static void* KeyInputEventThread(void *argv)
{
    KeyInputEnevtStruct *keyEvent = (KeyInputEnevtStruct *)argv;

    do {
        //按键事件回调
        if (gKeyInput.callback)
            gKeyInput.callback(gKeyInput.priv, keyEvent->key, keyEvent->value);
        //该值为0时,不触发长按事件
        if (gKeyInput.holdIntervalMs > 0)
        {
            //按下事件,经过2倍延时后切换为长按事件
            if (keyEvent->value == 1) {
                UbuntuDelayMs(gKeyInput.holdIntervalMs * 2);
                keyEvent->value = 2;
            }
            //长按事件时间间隔
            else if (keyEvent->value == 2)
                UbuntuDelayMs(gKeyInput.holdIntervalMs);
        }
        //周期触发长按事件
    } while (gKeyInput.state == 1 && keyEvent->value == 2 && 
        gKeyInput.keyArray[keyEvent->index] == keyEvent->key);

    gKeyInput.eventThreadCount -= 1;
    free(keyEvent);
    return NULL;
}

static void KeyInputReadEvent()
{
    struct input_event event;
    KeyInputEnevtStruct *keyEvent;
    int32_t index;

    if (read(gKeyInput.fd, &event, sizeof(event)) > 0)
    {
        if (event.type == EV_KEY)
        {
            // KEYINPUT_INFO("type: %d, key: %d, value: %d \r\n",
            //     event.type, event.code, event.value);
            //没有回调函数 || 按键按住事件(value=2)
            if (!gKeyInput.callback || event.value > 1)
                return;
            //按键按下时注册到数组,释放时清除
            index = 0;
            if (event.value == 1)
                index = _arrayAdd(gKeyInput.keyArray, gKeyInput.keyNum, event.code);
            else
                _arrayClear(gKeyInput.keyArray, gKeyInput.keyNum, event.code);
            //参数准备
            keyEvent = (KeyInputEnevtStruct *)calloc(1, sizeof(KeyInputEnevtStruct));
            keyEvent->key = event.code;
            keyEvent->value = event.value;
            keyEvent->index = index;
            //抛线程,在异步线程中触发用户回调函数
            gKeyInput.eventThreadCount += 1;
            UbuntuNewThread(keyEvent, &KeyInputEventThread);
        }
    }
}

static void* KeyInputThread(void *argv)
{
#if 0 // select
    fd_set fds;
    struct timeval tv = {
        .tv_sec = 0,
        .tv_usec = 100000, // 100ms超时
    };
#elif 1 // poll
    int32_t ret;
    struct pollfd fds[1];
    fds[0].fd = gKeyInput.fd;
    fds[0].events = POLLIN;
#endif

    while (gKeyInput.state == 1)
    {
#if 0 // select
        FD_ZERO(&fds);
        FD_SET(gKeyInput.fd, &fds);
        if (select(gKeyInput.fd + 1, &fds, NULL, NULL, &tv) > 0)
            KeyInputReadEvent();
#elif 1 // poll
        if ((ret = poll(fds, 1, 100)) < 0)
            KEYINPUT_ERR("poll error %d \r\n", ret);
        if (ret > 0 && fds[0].revents)
            KeyInputReadEvent();
#else   // 阻塞读(不利于及时退出线程)
        KeyInputReadEvent();
#endif
    }

    gKeyInput.state = 0;
    return NULL;
}

//callback函数原型 void callback(void *priv, int32_t key, int32_t value);
int32_t KeyInputInit(
    const char *devPath,
    int32_t holdIntervalMs, //按键按住时,定时触发事件间隔ms(为0表示不触发)
    int32_t maxKeyDown, //最大同时按下按键数量(当 holdIntervalMs > 0 时才有意义)
    void *priv,
    void (*callback)(void*, int, int))
{
    if (gKeyInput.state) {
        KEYINPUT_ERR("failed, thread is running\r\n");
        return -1;
    }

    gKeyInput.fd = open(devPath, O_RDONLY);
    if (gKeyInput.fd < 1) {
        KEYINPUT_ERR("open %s failed\r\n", devPath);
        return -1;
    }

    if (gKeyInput.keyArray)
        free(gKeyInput.keyArray);
    gKeyInput.keyNum = maxKeyDown < 1 ? 1 : maxKeyDown;
    gKeyInput.keyArray = (int*)calloc(gKeyInput.keyNum, sizeof(int));

    gKeyInput.holdIntervalMs = holdIntervalMs < 0 ? 0 : holdIntervalMs;
    gKeyInput.priv = priv;
    gKeyInput.callback = callback;
    gKeyInput.state = 1;

    UbuntuNewThread(NULL, KeyInputThread);
    return 0;
}

void KeyInputDeInit()
{
    if (gKeyInput.state)
        gKeyInput.state = 2;
}
